package com.gaga.metadata.driver;



import com.gaga.metadata.common.assertion.Asserts;
import com.gaga.metadata.common.exception.TransFormException;
import com.gaga.metadata.entity.database.DataBaseColumn;
import com.gaga.metadata.entity.database.DataBaseSchema;
import com.gaga.metadata.entity.database.DataBaseTable;
import com.gaga.metadata.result.JdbcSelectResult;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.ServiceLoader;

/**
 * Driver
 *
 * @author liujia
 * @since 2021/7/19 23:15
 */
public interface Driver {

    static Optional<Driver> get(DriverConfig config) {
        Asserts.checkNotNull(config, "数据源配置不能为空");
        //SPI机制
        ServiceLoader<Driver> drivers = ServiceLoader.load(Driver.class);
        for (Driver driver : drivers) {
            if (driver.canHandle(config.getType())) {
                return Optional.of(driver.setDriverConfig(config));
            }
        }
        return Optional.empty();
    }

    static Driver build(DriverConfig config) {
        String key = config.getName();

        if (DriverPool.exist(key)) {
            return getHealthDriver(key);
        }
        Optional<Driver> optionalDriver = Driver.get(config);
        if (!optionalDriver.isPresent()) {
            throw new TransFormException("不支持数据源类型【" + config.getType() + "】，请在 lib 下添加扩展依赖");
        }
        Driver driver = optionalDriver.get().connect();
        DriverPool.push(key, driver);
        return driver;
    }

    static Driver getHealthDriver(String key) {
        Driver driver = DriverPool.get(key);
        if (driver.isHealth()) {
            return driver;
        } else {
            return driver.connect();
        }
    }

    Driver setDriverConfig(DriverConfig config);

    boolean canHandle(String type);

    String getType();

    String getName();

    String test();

    boolean isHealth();

    Driver connect();

    void close();

    List<DataBaseSchema> listSchemas();

    List<DataBaseTable> listTables(String schemaName, String tableName);

    List<DataBaseColumn> listColumns(String schemaName, String tableName);

    List<DataBaseSchema> getSchemasAndTables();

    List<DataBaseTable> getTablesAndColumns(String schemaName);

    /**
     * 表是不是存在主键
     *
     * @param schemaName
     * @param tableName
     * @return
     */
    boolean tableHasPrimaryKey(String schemaName, String tableName);

    /**
     * 表是不是包含这个列
     *
     * @param schemaName
     * @param tableName
     * @param columnName
     * @return
     */
    boolean tableHasThisColumn(String schemaName, String tableName, String columnName);

    DataBaseTable getTable(String schemaName, String tableName);

    boolean existTable(DataBaseTable table);

    boolean createTable(DataBaseTable table) throws Exception;

    /**
     * 创建表之前先删除
     *
     * @param table
     * @return
     * @throws Exception
     */
    boolean dropThenCreateTable(DataBaseTable table) throws Exception;

    boolean dropTable(DataBaseTable table) throws Exception;

    boolean truncateTable(DataBaseTable table) throws Exception;

    /**
     * 获取创建表的sql
     *
     * @param table
     * @return
     * @throws Exception
     */
    String getCreateTableSql(DataBaseTable table);

    String getDropTableSql(DataBaseTable table);

    String getTruncateTableSql(DataBaseTable table);

    boolean execute(String sql, DataBaseTable table) throws Exception;

    int executeUpdate(String sql) throws Exception;

    /**
     * 通过table 去调用查询
     *
     * @param table
     * @return
     */
    JdbcSelectResult jdbcSelectByTable(DataBaseTable table);

    JdbcSelectResult query(String sql, Integer limit);


    String getUninAllSql();


    /**
     * 通过table 去获取关联查询的sql
     *
     * @param table
     * @return
     * @throws Exception
     */
    String getSelectSql(DataBaseTable table);


    /**
     * 通过tableName，数据list，批量insert数据
     */
    boolean batchInsertTableList(String schemaName, String tableName, List<String> columns, List<Map<Integer, String>> dataList);

    /**
     * 获取count
     */
    Integer getCount(String sql);

    /**
     * 获取某一列是否有数据
     */
    boolean hasColumnData(String tableName, String columnName);

    /**
     * 获取表里面是不是有数据
     *
     * @param tableName
     * @return
     */
    boolean tableHasData(String tableName);

    /**
     * 处理多个操作逻辑
     *
     * @param tableList
     * @return
     * @throws Exception
     */
    boolean handlerOperList(List<DataBaseTable> tableList) throws Exception;


    boolean addColumn(DataBaseTable table) throws Exception;

    boolean addIndex(DataBaseTable table) throws Exception;

    String getAddColunmSql(DataBaseTable table);

    String getAddIndexSql(DataBaseTable table);


    boolean updateColumn(DataBaseTable table) throws Exception;

    boolean recreateColumn(DataBaseTable table) throws Exception;

    String getUpdateColunmSql(DataBaseTable table);


    boolean delColumn(DataBaseTable table) throws Exception;

    boolean delIndex(DataBaseTable table) throws Exception;

    String getDelColunmSql(DataBaseTable table);

    String getDelIndexSql(DataBaseTable table);


    boolean updateTable(DataBaseTable table) throws Exception;

    String getUpdateTableSql(DataBaseTable table);


    /**
     * 通过table 去获取where后字段notnull的sql
     *
     * @param columnName
     * @return
     * @throws Exception
     */
    String getNotNullSql(String columnName);

    boolean updateIndex(DataBaseTable dataBaseTable) throws Exception;

    String getUpdateIndexSql(DataBaseTable table);
}
